package com.my.lowversionbootes.util;

import com.my.lowversionbootes.PageParam;
import com.my.lowversionbootes.PageResult;
import org.apache.http.HttpHost;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.support.replication.ReplicationResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Description
 * @Author maye
 * @Date 2019/7/13
 * @Version V1.0.0
 */
public class ESHighLevelRestUtil {
    static RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("118.24.203.146", 9200, "http"), new HttpHost("118.24.203.146", 9201, "http")));

    /**
     * 属性名称
     */
    private static final String PROPERTIES = "properties";
    /**
     * 分片数量
     */
    private static final String INDEX_NUMBER_OF_SHARDS = "index.number_of_shards";
    /**
     * 副本数量
     */
    private static final String INDEX_NUMBER_OF_REPLICAS = "index.number_of_replicas";

    /**
     * 默认类型名称
     */
    private static final String INIT_TYPE = "_doc";

    /**
     * 查询超时时间 默认秒
     */
    private static final Integer QUERT_TIMEOUT = 30;


    /**
     * 验证索引是否存在
     *
     * @param index 索引名称
     * @return 是否存在
     */
    public boolean indexExists(String index) {
        GetIndexRequest request = new GetIndexRequest(index);
        request.local(false);
        request.humanReadable(true);
        try {
            return client.indices().exists(request, RequestOptions.DEFAULT);
        } catch (IOException exception) {
            throw new RuntimeException("ESHighLevelRestUtil.indexExists异常", exception);
        }
    }

    /**
     * @param index      索引名称
     * @param properties 结构: {name:{type:text}} {age:{type:integer}}
     * @return 执行结果
     */
    public <T> boolean indexCreate(String index, T properties) {

        if (indexExists(index)) {
            return true;
        }

        CreateIndexRequest createIndexRequest = initCreateIndexRquest(index);

        Map<String, Object> mapping = new HashMap<>();
        mapping.put(PROPERTIES, properties);
        createIndexRequest.mapping(ConvertUtil.getObjToStr(mapping), XContentType.JSON);
        createIndexRequest.alias(new Alias(index + "_alias"));
        CreateIndexResponse createIndexResponse;
        try {
            createIndexResponse = client.indices().create(
                    createIndexRequest, RequestOptions.DEFAULT);
        } catch (IOException exception) {
            throw new RuntimeException("ESHighLevelRestUtil.indexCreate异常", exception);
        }
        return createIndexResponse.isAcknowledged();
    }

    public CreateIndexRequest initCreateIndexRquest(String index) {
        CreateIndexRequest request = new CreateIndexRequest(index);
        request.settings(Settings.builder().put(INDEX_NUMBER_OF_SHARDS, 3)
                .put(INDEX_NUMBER_OF_REPLICAS, 2));
        return request;
    }

    /**
     * 删除索引
     *
     * @param index 索引名称
     * @return 删除结果
     */
    public boolean indexDelete(String index) {
        AcknowledgedResponse deleteResponse;
        try {
            DeleteIndexRequest request = new DeleteIndexRequest(index);
            deleteResponse = client.indices().delete(
                    request, RequestOptions.DEFAULT);
            return deleteResponse.isAcknowledged();
        } catch (IOException exception) {
            throw new RuntimeException("ESHighLevelRestUtil.indexDelete异常", exception);
        } catch (ElasticsearchException exception) {
            if (exception.status() == RestStatus.NOT_FOUND) {
                return true;
            }
        }
        return false;
    }


    /**
     * 创建更新文档
     *
     * @param index      索引名称
     * @param documentId documentId
     * @param jsonData   jsonData
     * @return 创建结果
     */
    public boolean documentUpsert(String index, String documentId, Map jsonData) {
        UpdateRequest updateRequest = new UpdateRequest(index, INIT_TYPE, documentId);

        updateRequest.upsert(jsonData, XContentType.JSON);
        updateRequest.doc(jsonData);

        try {
            ReplicationResponse.ShardInfo shardInfo = client.update(updateRequest, RequestOptions.DEFAULT).getShardInfo();
            if (shardInfo.getFailed() > 0) {
                throw new RuntimeException(shardInfo.getFailures()[0].reason());
            }
            return true;
        } catch (IOException exception) {
            throw new RuntimeException("ESHighLevelRestUtil.documentCreate异常", exception);
        }

    }

    /**
     * 查找文档根据id
     *
     * @param id           id
     * @param index        索引名称
     * @param responseType 需要序列化的类型
     * @return 创建结果
     */
    public <T> T getDocumentById(String index, String id, Class<T> responseType) {
        GetRequest getRequest = new GetRequest(index, INIT_TYPE, id);
        try {
            GetResponse documentFields = client.get(getRequest, RequestOptions.DEFAULT);
            if (documentFields.isExists()) {
                String sourceAsString = documentFields.getSourceAsString();
                return ConvertUtil.objToObj(sourceAsString, responseType);
            } else {
                throw new RuntimeException("未找到文档");
            }
        } catch (IOException exception) {
            throw new RuntimeException("ESHighLevelRestUtil.getDocumentById异常", exception);
        }


    }


    /**
     * 删除文档根据id
     *
     * @param id    id
     * @param index 索引名称
     * @return 创建结果
     */
    public boolean deleteDocumentById(String index, String id) {
        DeleteRequest deleteRequest = new DeleteRequest(index, INIT_TYPE, id);
        try {
            DeleteResponse deleteResult = client.delete(deleteRequest, RequestOptions.DEFAULT);
            ReplicationResponse.ShardInfo shardInfo = deleteResult.getShardInfo();
            if (shardInfo.getFailed() > 0) {
                throw new RuntimeException(shardInfo.getFailures()[0].reason());
            }
            return true;
        } catch (IOException exception) {
            throw new RuntimeException("ESHighLevelRestUtil.deleteDocumentById异常", exception);
        }
    }

    /**
     * 根据条件查询文档返回分页信息
     *
     * @param queryBuilder 查询条件
     * @param pageParam    分页信息
     * @param index        索引名称可以是多个
     * @return 创建结果
     */
    public <T> PageResult<T> queryDocument(QueryBuilder queryBuilder, PageParam pageParam, Class<T> responseType, String... index) {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(queryBuilder);
        sourceBuilder.from(pageParam.getPageNum());
        sourceBuilder.size(pageParam.getPageSize());
        sourceBuilder.timeout(new TimeValue(QUERT_TIMEOUT, TimeUnit.SECONDS));
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.source(sourceBuilder);

        try {
            List<T> list = new ArrayList<>();
            SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits hits = search.getHits();
            SearchHit[] searchHits = hits.getHits();
            for (SearchHit hit : searchHits) {
                list.add(ConvertUtil.objToObj(hit.getSourceAsString(), responseType));
            }
            return new PageResult<>(pageParam.getPageNum()
                    , pageParam.getPageSize(), hits.getTotalHits(), list);
        } catch (IOException exception) {
            throw new RuntimeException("ESHighLevelRestUtil.deleteDocumentById异常", exception);
        }
    }

}